import time
import inspect
from threading import Thread,Lock

def _make_key(fn,*args,**kwargs):
    target = {}
    sig = inspect.signature(fn)
    params = sig.parameters
    target.update(zip(params.keys(), args))
    target.update(kwargs)
    target.update({k: v.default for k, v in params.items() if k not in target.keys()})
    key = tuple(sorted(target.items()))
    return key,target



class Cache:
    local_cache = {}

    def __init__(self,fn,duration=None):
        self.fn = fn
        self.duration = duration
        if self.duration is not None:
            self.lock = Lock()   #如果需要清理，由于另开线程监控，要保证local_cache不能并发的读写，要用到锁
            Thread(target=self.expire_handle).start()

    def put(self,*args,**kwargs):         #缓存结果到local_cache中
        key,target = _make_key(self.fn,*args,**kwargs)
        if key not in self.local_cache.keys():
            ret = self.fn(**target)
            if self.duration is None:
                self.local_cache[key] = ret
            else:
                with self.lock:
                    self.local_cache[key] = ret,time.time()
        else:
            if self.duration is not None:
                with self.lock:
                    self.local_cache[key][1] = time.time()  #对于需要定期清理缓存的，如果参数已经缓存，再次缓存，只要改变时间戳

    def get(self,*args,**kwargs):
        key, target = _make_key(self.fn, *args, **kwargs)
        if key in self.local_cache.keys():
            if self.duration is None:
                print('查询到缓存结果',self.local_cache[key])
                return self.local_cache[key]
            else:
                with self.lock:
                    print('查询到缓存结果', self.local_cache[key][0])
                    return self.local_cache[key][0]

        print("未进行缓存，无查询结果")

    def expire_handle(self):  #清理过期缓存
        while True:
            expire_keys = []
            for key,(res,timestamp) in self.local_cache.items():
                if time.time() - timestamp >= self.duration:
                    expire_keys.append(key)
            with self.lock:
                for key in expire_keys:
                    self.local_cache.pop(key)
            time.sleep(0.02)

def add(x=1,y=2):
    time.sleep(3)
    print('res-----',x+y)
    return x + y

foo = Cache(add,duration=3)
foo.put(y=2,x=1)
foo.get(1,2)         #所有参数形式都查一次
foo.get(y=2)
foo.get(x=1)

time.sleep(3.5)  #
foo.get(1,2)          #再次查询检查缓存有没失效